/**********************************************************************
 *                                                                    *
 * tgt - Tiny Graphics Toolbox                                        *
 *                                                                    *
 * Copyright (C) 2006-2008 Visualization and Computer Graphics Group, *
 * Department of Computer Science, University of Muenster, Germany.   *
 * <http://viscg.uni-muenster.de>                                     *
 *                                                                    *
 * This file is part of the tgt library. This library is free         *
 * software; you can redistribute it and/or modify it under the terms *
 * of the GNU Lesser General Public License version 2.1 as published  *
 * by the Free Software Foundation.                                   *
 *                                                                    *
 * This library is distributed in the hope that it will be useful,    *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the       *
 * GNU Lesser General Public License for more details.                *
 *                                                                    *
 * You should have received a copy of the GNU Lesser General Public   *
 * License in the file "LICENSE.txt" along with this library.         *
 * If not, see <http://www.gnu.org/licenses/>.                        *
 *                                                                    *
 **********************************************************************/

#include "tgt/quadric.h"
#include "tgt/memorymanager.h"
#include "tgt/guiapplication.h"
#include "tgt/glcanvas.h"
#include "tgt/toolkitfactory.h"
#include "tgt/painter.h"
#include "tgt/camera.h"

using namespace tgt;

GUIApplication* tgtApp;
GLCanvas* glCanvas;

Timer* timer;

float size = 1.f;
float epsilon = 0.01f;
int timerMSecs = 40;

class MyPainter : public Painter {
public:
    MyPainter(GLCanvas* canvas) : Painter(canvas) {};
    virtual void paint();
    virtual void init();
    virtual void sizeChanged(const ivec2& size);
};

void MyPainter::paint() {
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    // set Camera
    getCamera()->look();

    // render sphere
    Sphere sphere(size, 64, 32);
    sphere.render();
}

void MyPainter::init() {
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    getCamera()->setPosition(vec3(0.f,0.f,3.f));

    glColor4f(1.f, 0.f, 0.f, 1.f);
}

void MyPainter::sizeChanged(const ivec2& size) {
    glViewport(0,0,size.x,size.y);
    getCamera()->setRatio((float) size.x/size.y);
}


class MyEventListener : public EventListener {
    void keyEvent(KeyEvent *e);
    void timerEvent(TimeEvent *e);
};

void MyEventListener::keyEvent(KeyEvent *e) {
    // only handle key-down events
    if (e->pressed()) {
        switch (e->keyCode()) {
        case '+':
            size *= 2;
            break;
        case '-':
            size /= 2;
            break;
        case KeyEvent::K_LEFT:
            timerMSecs *= 2;
            if (timerMSecs > 1000)
                timerMSecs = 1000;
            std::cout << "Timer is set to " << timerMSecs << " milliseconds.\n";
            timer->stop();
            timer->start(timerMSecs, 0);
            break;
        case KeyEvent::K_RIGHT:
            timerMSecs /= 2;
            if (timerMSecs == 0)
                timerMSecs = 1;
            std::cout << "Timer is set to " << timerMSecs << " milliseconds.\n";
            timer->stop();
            timer->start(timerMSecs, 0);
            break;
        case KeyEvent::K_ESCAPE:
            tgtApp->quit();
            break;
        default:
            // generate a color of the keycode:
            glColor4f( (float)e->keyCode()/KeyEvent::K_LAST,
                       1.f - (float)e->keyCode()/KeyEvent::K_LAST,
                       (float)((e->keyCode()+KeyEvent::K_LAST/2)%KeyEvent::K_LAST)/KeyEvent::K_LAST,
                       1.f);
            break;
        }
        glCanvas->update();
        e->accept();
    }
}

void MyEventListener::timerEvent(TimeEvent *e) {
    if (e->getTimer() == timer) {
        if (fabs(size - 1.0f) > 2 * epsilon) {
            if (size < 1.0f)
                size += epsilon;
            else
                size -= epsilon;
            glCanvas->update();
        }
        e->accept();
    }
}


int main(int argc, char** argv) {
    
    std::cout
        << "tgt Sample Program: events" << std::endl
        << std::endl
        << "Shows tgt's event system and how events can be caught to make things happen." << std::endl
        << std::endl
        << "Usage:" << std::endl
        << "+/-: Change sphere size" << std::endl
        << "Left/Right arrow key: shrink/enlage timer frequency" << std::endl
        << "Esc: exit" << std::endl
        << "any other key: Change sphere color based on keycode" << std::endl
        << std::endl;
    

    tgtApp = ToolkitFactory::createApplication(argc, argv);

    glCanvas = ToolkitFactory::createCanvas("tgt Example: Event Handling");
    tgtApp->addCanvas(glCanvas);

    tgtApp->init();

    Camera camera;
    glCanvas->setCamera(&camera);

    MyPainter painter(glCanvas);
    glCanvas->setPainter(&painter);


    MyEventListener eventListener;
    glCanvas->getEventHandler()->addListenerToFront(&eventListener);

    timer = ToolkitFactory::createTimer( glCanvas->getEventHandler() );
    timer->start(timerMSecs, 0);

    tgtApp->run();

    delete glCanvas;
    delete tgtApp;

    return 0;
}
